﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Reflection;
using System.Text.RegularExpressions;

using LINQToolKit.Query;
using LINQToolKit.Query.Rules;
using LINQToolKit.GData;

namespace LINQToolKit.Douban
{
    internal class DoubanQueryTranslator : GDataTranslator
    {
        private const string Seperator = "{0}&[[{1}-{2}]]";
        private const string Pattern = @"&\[\[.+\]\]";

        public DoubanQueryTranslator()
            : base(QueryRule.Default)
        {

        }

        public DoubanQueryTranslator(QueryRule rule)
            : base(rule)
        {

        }

        protected override TranslatorBase CreateSubTranslator()
        {
            return new DoubanQueryTranslator(this.Rule);
        }

        public override IList<string> GetQueries(Expression expression)
        {
            var list = base.GetQueries(expression);

            for (int i = 0; i < list.Count; i++)
            {
                list[i] = Regex.Replace(list[i], Pattern, string.Empty);
            }

            return list;
        }

        protected override IList<string> CombineAndAlsoQuery(IList<string> left, IList<string> right)
        {
            return left.Union(right, this.GetQueryComparer()).ToList();
        }

        protected override string TranslateUnkownQueryMethod(MethodCallExpression m)
        {
            string result = base.TranslateUnkownQueryMethod(m);

            // the keywrod search
            if (m.Method.Name == "Has" &&
                m.Method.DeclaringType == typeof(GDataQueryExt))
            {
                var entityType = m.Arguments[0].Type.GetGenericArguments()[0];
                var rule = this.Rule.Types[entityType];

                if (rule.Queries.ContainsKey("keyword"))
                {
                    return rule.Queries["keyword"];
                }
            }

            return result;
        }

        protected override string TranslateUndefinedMemberAccess(
            Type entityType, MemberExpression expr, ConstantExpression value, ExpressionType oper)
        {
            // the undefiend memeber access is regarded as keyword search
            var rule = this.Rule.Types[entityType];

            if (rule.Queries.ContainsKey("keyword"))
            {
                if (oper == ExpressionType.Equal)
                {
                    this.IncludeKeyword(value.Value.ToString());
                }
                else if (oper == ExpressionType.NotEqual)
                {
                    this.ExcludeKeyword(value.Value.ToString());
                }

                return string.Format(
                    Seperator, rule.Queries["keyword"], expr.Member.Name, value.Value);
            }

            return null;
        }
    }
}
